package inventory.shiro.realm;

import inventory.common.UserStatusEnum;
import inventory.entity.Manager;
import inventory.entity.Role;
import inventory.entity.User;
import inventory.mappers.ManagerMapper;
import inventory.mappers.RoleMapper;
import inventory.mappers.UserMapper;
import org.apache.shiro.authc.*;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import java.util.Date;


public class UserRealm extends AuthenticatingRealm {

    @Autowired
    private ApplicationContext applicationContext;

//    @Autowired
//    UserMapper userMapper;

    //授权,在调用requireRole或者requirePermission时会进入该方法
//    @Override
//    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//
//        System.out.println("进入自定义userRealm授权...");
//
//        //查到权限数据，返回授权信息
//        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//
//        //获取在认证的时候存入的checkUser
//        User user = (User) principals.getPrimaryPrincipal();
//
//        //添加角色信息
//        Set<String> roleSet = new HashSet<>();
//        roleSet.add(user.getRoleId());
//        simpleAuthorizationInfo.addRoles(roleSet);
//
//        //添加权限信息
//        PermissionRecordPoMapper permissionRecordPoMapper = (PermissionRecordPoMapper) applicationContext.getBean("permissionRecordPoMapper");
//        List<PermissionRecordPo> permissionRecordPoList = permissionRecordPoMapper.selectList(new EntityWrapper<PermissionRecordPo>().eq("user_id", user.getManagerId()));
//        List<String> permissionRecords = new ArrayList<>();
//        for (PermissionRecordPo item: permissionRecordPoList) {
//            permissionRecords.add(item.getPermission());
//        }
//        simpleAuthorizationInfo.addStringPermissions(permissionRecords);
//
//        return simpleAuthorizationInfo;
//    }

    //认证，subject.login()的时候会进去该方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        System.out.println("进入自定义userRealm认证...");

        //获取用户名密码,即在subject.login(token)中token的值
        User tempUser = new User();
        tempUser.setWorkId((String) token.getPrincipal());  //token.getPrincipal()
        String password = new String((char[]) token.getCredentials());  //token.getCredentials()

        System.out.println("user的workId:"+tempUser.getWorkId());
        System.out.println("user的password:"+password);


        //从applicationContext中拿到userMapper
        UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
        RoleMapper roleMapper = (RoleMapper) applicationContext.getBean("roleMapper");
        ManagerMapper managerMapper = (ManagerMapper) applicationContext.getBean("managerMapper");

        //查询是否有对应用户
        User checkUser = userMapper.selectOne(tempUser);
        if (checkUser==null){
            throw new UnknownAccountException(tempUser.getWorkId());
        }

        //-------检查账户的管理员是否过期 start-------
        //通过以下，查询到这和用户对应市的管理员id
        Role tempRole = new Role();
        tempRole.setRoleId(checkUser.getPid());
        while (true){
            Role role = roleMapper.selectOne(tempRole);
            if (role==null){
                break;
            }
            tempRole.setRoleId(role.getPid());
        }
        //根据得到的管理员id查询对应的管理员
        Manager tempManager = new Manager();
        tempManager.setManagerId(tempRole.getRoleId());
        Manager manager = managerMapper.selectOne(tempManager);

        Date timeLimit = manager.getTimeLimit();
        Date now = new Date();
        //如果现在的时间在时限之后，则不允许登录
        if (now.after(timeLimit)){
            throw new ExpiredCredentialsException("管理员账号已到期");
        }
        if (manager.getStatus().equals(UserStatusEnum.LOCK.getCode())){
            throw new LockedAccountException("管理员账号被封");
        }
        //-------检查账户的管理员是否过期 end-------

        //交给AuthenticationRealm使用CredentialsMatcher进行密码匹配
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                checkUser, //认证过后的安全用户对象，包含了该用户所有信息
                //下面的参数才是真正拿去做密码比对的，上面的checkUser就存入了subject，方便其他方法调用
                checkUser.getPassword(), //密码
                ByteSource.Util.bytes(checkUser.getSalt()), //salt
                getName() //realm name
        );
        return authenticationInfo;

    }
}
